#define WIN32_LEAN_AND_MEAN
#include <algorithm>
#include <locale>
#include <Windows.h>
#include "resource.h"
#include "logger.h"

namespace cyb
{

/*
 * Slightly modified version of the original version from an MSDN community contribution from "Infinitework"
 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360%28v=vs.85%29.aspx
 */
static std::string GetLastErrorText()
{
	LPTSTR pTemp = NULL;

     DWORD retSize = FormatMessage(
		 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
		 NULL,
		 GetLastError(),
		 LANG_NEUTRAL,
		 (LPTSTR) &pTemp,
		 0,
		 NULL );
     if ( !retSize || pTemp == NULL ) 
	 {
          return std::string();
     }
    
     pTemp[strlen( pTemp ) - 2] = '\0'; // remove cr and newline character
	 std::string message( pTemp );
	 LocalFree( (HLOCAL) pTemp );

     return message;
}

FileResource::FileResource( const std::string& filename ) :
	Resource( filename )
{
}

bool FileResource::Load()
{
	HANDLE fileHandle = CreateFile( Filename().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr );
	if ( fileHandle == INVALID_HANDLE_VALUE )
	{
		CYB_WARNING( false, "Failed to open ", Filename(), ": ", GetLastErrorText() );
		return false;
	}

	DWORD fileSize = GetFileSize( fileHandle, nullptr );
	if ( fileSize == INVALID_FILE_SIZE || fileSize == 0 )
	{
		CYB_WARNING( false, "File ", Filename(), " has invalid filesize: ", fileSize );
		return false;
	}

	std::unique_ptr<char[]> buffer = std::make_unique<char[]>( fileSize + 1 );
	if (ReadFile( fileHandle, buffer.get(), fileSize, nullptr, nullptr ) != TRUE )
	{
		CYB_WARNING( false, "Failed to read ", fileSize, "bytes from ", Filename(), ": ", GetLastErrorText() );
		return false;
	}
	
	buffer[fileSize] = '\0';
	m_buffer = std::move( buffer );
	m_bufferSize = fileSize;
	m_isLoaded = true;

	return true;
}

void FileResource::UnLoad()
{
	m_buffer.release();
	m_bufferSize = 0;
	m_isLoaded = false;
}

const size_t FileResource::AllocatedSize() const
{
	return m_bufferSize;
}

const std::string& FileResource::Filename() const
{
	return ResourceName();
}


const char* FileResource::Buffer() const
{
	return m_buffer.get();
}

char* FileResource::WriteableBuffer( size_t* bufferSize )
{
	if ( bufferSize != nullptr )
	{
		*bufferSize = m_bufferSize;
	}

	return m_buffer.get();
}

}	// namespace cyb